#include "tcp.h"
#include "cJSON.h"
#define IP_STM32 "192.168.175.179" // ubuntu地址
#define PORT_STM32 8002            // port
#define msg_key 0x200
#define shm_key 0x300
// 主函数，程序入口点
int main(int argc, char *argv[])
{
    int servfd = -1; // 服务器文件描述符初始化为-1，表示未初始化
    // 创建TCP服务器套接字
    servfd = create_tcp_server_socket(IP_STM32, PORT_STM32, 9);
    // 启动服务器主循环
    server_main_loop(servfd);

    // 关闭服务器套接字
    close(servfd);
    servfd = -1; // 将文件描述符重置为-1，表示关闭
    return 0;    // 返回0表示成功
}

// 创建TCP服务器套接字
int create_tcp_server_socket(const char *psvrip, unsigned short svrport, int backlog)
{
    int servfd = -1;             // 服务器文件描述符初始化为-1，表示未初始化
    struct sockaddr_in servaddr; // 服务器地址结构体
    int ret = 0;                 // 返回值初始化为0

    // 创建套接字
    servfd = socket(AF_INET, SOCK_STREAM, 0);
    printf("TCP mode\n");
    // 初始化服务器地址结构体
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;         // 设置地址族为IPv4
    servaddr.sin_port = htons(svrport);    // 设置端口号
    inet_aton(psvrip, &servaddr.sin_addr); // 将点分十进制IP地址转换为二进制
    // 绑定套接字到指定的地址和端口
    ret = bind(servfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    printf("端口号: %d  ,添加地址为 : %s \n", svrport, psvrip);
    // 监听连接请求
    ret += listen(servfd, backlog);
    printf("监听完成\n");
    // 检查错误
    if (ret)
    {
        printf("bind or listen failed\n");
        close(servfd); // 关闭套接字
        servfd = -1;   // 将文件描述符重置为-1，表示关闭
        return -1;     // 返回错误码-1
    }
    return servfd; // 返回服务器文件描述符
}

// 服务器主循环
int server_main_loop(int fd)
{
    int datafd = -1; // 数据文件描述符初始化为-1，表示未初始化
    pthread_t tid_1; // 线程1的ID
    pthread_t tid_2; // 线程2的ID
    int ret = 0;     // 返回值初始化为0

    // 无限循环，等待客户端连接
    while (1)
    {
        printf("等待客户端的连接\n");
        // 接受客户端连接
        datafd = accept(fd, NULL, NULL);
        printf("客户端的连接完成\n");

        // 检查错误
        if (datafd < 0)
        {
            if (errno == EINTR)
                continue; // 如果是中断错误，继续
            else
            {
                printf("Accept error\n");
                break; // 否则，跳出循环
            }
        }
        // 创建线程1：处理客户端数据
        ret = pthread_create(&tid_1, NULL, handle_client, (void *)(long)datafd);
        if (ret != 0)
        {
            close(datafd); // 关闭数据套接字
            datafd = -1;   // 将文件描述符重置为-1，表示关闭
            printf("pthread_create failed for handle_client\n");
            continue; // 继续下一次循环
        }

        // 创建线程2：初始化消息队列
        ret = pthread_create(&tid_2, NULL, masget_init, (void *)(long)datafd);
        if (ret != 0)
        {
            close(datafd); // 关闭数据套接字
            datafd = -1;   // 将文件描述符重置为-1，表示关闭
            printf("pthread_create failed for masget_init\n");
            continue; // 继续下一次循环
        }
    }
    return 0; // 返回0表示成功
}

// 处理客户端数据的线程函数
void *handle_client(void *parg)
{
    int datafd = (int)(long)parg;   // 从参数中获取数据文件描述符
    pthread_detach(pthread_self()); // 分离线程，不需要与主线程同步
    char arr[1024];                 // 定义数组用于存储读取的数据
    ssize_t bytes_read;             // 用于存储读取的字节数

    printf("创建共享内存.....\n");
    // 创建共享内存
    int shmid = shmget(shm_key, sizeof(arr), IPC_CREAT | IPC_EXCL | 0666);
    if (shmid == -1)
    { // 如果创建失败
        // 检查错误是因为已经存在还是其他原因
        if (errno == EEXIST)
            shmid = shmget(shm_key, sizeof(arr), 0);
        else
        {
            perror("shmget");
            close(datafd); // 关闭数据套接字
            return NULL;   // 返回NULL表示失败
        }
    }

    char *p = shmat(shmid, NULL, 0); // 将共享内存映射到进程地址空间
    if (p == (void *)-1)
    {                    // 如果映射失败
        perror("shmat"); // 打印错误信息
        close(datafd);   // 关闭数据套接字
        return NULL;     // 返回NULL表示失败
    }
    printf("共享内存创建完成\n");
    printf("读取STM32数据....\n");
    // 循环读取数据
    while ((bytes_read = read(datafd, arr, sizeof(arr) - 1)) > 0)
    {
        arr[bytes_read] = '\0'; // 确保字符串以空字符结束
        //       if (strcmp(arr, "STM32_ID_01") == 0)
        //           write(datafd, arr, bytes_read + 1); // 如果数据是特定标识符，直接回写给客户端
        //       else
        //        {
        printf("写入的数据：%s\n", arr); // 打印读取的数据
        memcpy(p, arr, bytes_read + 1);  // 将数据复制到共享内存
                                         //       }
        memset(arr, 0, sizeof(arr));     // 清空数组，准备下一次读取
    }
    if (bytes_read < 0)
        perror("read"); // 如果读取失败，打印错误信息
    else
        printf("Client closed connection\n"); // 否则，打印客户端关闭连接的信息
    close(datafd);                            // 关闭数据套接字
    shmdt(p);                                 // 分离共享内存

    return NULL; // 返回NULL表示线程结束
}

// 消息队列初始化线程函数
void *masget_init(void *parg)
{
    int datafd = (int)(long)parg;   // 从参数中获取数据文件描述符
    struct msgbuf mb;               // 定义消息缓冲区结构体
    int msgid, ret;                 // 消息队列ID和返回值
    pthread_detach(pthread_self()); // 分离线程，不需要与主线程同步

    // 创建消息队列
    msgid = msgget(msg_key, IPC_CREAT | 0666);
    if (msgid < 0)
    {
        perror("msgget");
        return NULL; // 如果创建失败，返回NULL
    }
    printf("信息队列创建成功,msg_id:%d\n", msgid);

    // 无限循环，从消息队列接收消息
    while (1)
    {
        ret = msgrcv(msgid, &mb, 512, MSG_TYPE, 0); // 从消息队列接收消息
        if (ret < 0)
        {
            perror("msgrcv"); // 如果接收失败，打印错误信息
            return NULL;      // 返回NULL表示线程结束
        }
        mb.mtext[ret] = '\0';                             // 确保字符串以空字符结束
        write(datafd, mb.mtext, ret);                     // 将接收到的数据写入数据套接字
        printf("收到消息队列中JSON数据: %s\n", mb.mtext); // 打印接收到的消息
    }
}
